#include "mainwindow.h"
#include <QtWidgets>
#include "mylabel.h"
#include <QIcon>
#include <QSerialPortInfo>
#include <qDebug>

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent), m_PortCombox(new MyComboBox()), m_BaudCombox(new MyComboBox()), m_DataCombox(new MyComboBox()),
      m_CheckCombox(new MyComboBox()), m_StopCombox(new MyComboBox()), m_OpenButton(new QPushButton(" 打开")),
      m_SendFmtCombox(new MyComboBox()), m_ShowFmtCombox(new MyComboBox()), m_ClearButton(new QPushButton(" 清空")),
      m_textEdit(new MyPlainTextEdit()), m_CmdComboBox(new QComboBox()), m_SendButton(new QPushButton("Send"))
{
    setupUi();
    m_portOpened = false;
    m_showHex = true;
    m_sendHex = true;
    connect(&m_serialPort, &QSerialPort::readyRead, this, &MainWindow::handleReadyRead);
    //connect(&m_recvThread, &RecvThread::recvRequest, this, &MainWindow::threadRecvReq);
}

MainWindow::~MainWindow()
{
    if (m_portOpened) {
        m_serialPort.close();
    }
}

void MainWindow::setupUi()
{
    resize(1024, 600);
    m_OpenIcon = QIcon(":/images/open.png");
    m_CloseIcon = QIcon(":/images/close.png");
    m_ClearIcon = QIcon(":/images/clear.png");

    auto comToolBar = addToolBar("Com");
    comToolBar->setFixedHeight(30);
    auto portLabel = new MyLabel(" 端口：");
    comToolBar->addWidget(portLabel);
    connect(m_PortCombox, SIGNAL(clicked(bool)), this, SLOT(portComboxClicked(bool)));
    QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo& info : infos) {
        m_PortCombox->addItem(info.portName());
    }
    comToolBar->addWidget(m_PortCombox);

    auto baudLabel = new MyLabel(" 波特率：");
    m_BaudCombox->addItem("4800");
    m_BaudCombox->addItem("9600");
    m_BaudCombox->addItem("19200");
    m_BaudCombox->addItem("38400");
    m_BaudCombox->addItem("57600");
    m_BaudCombox->addItem("115200");
    m_BaudCombox->addItem("128000");
    m_BaudCombox->addItem("256000");
    m_BaudCombox->setEditable(true);
    m_BaudCombox->setCurrentIndex(5);
    comToolBar->addWidget(baudLabel);
    comToolBar->addWidget(m_BaudCombox);

    auto dataLabel = new MyLabel(" 数据位：");
    m_DataCombox->addItem("6");
    m_DataCombox->addItem("7");
    m_DataCombox->addItem("8");
    m_DataCombox->setCurrentIndex(2);
    comToolBar->addWidget(dataLabel);
    comToolBar->addWidget(m_DataCombox);

    auto checkLabel = new MyLabel(" 校验位：");
    m_CheckCombox->addItem("No Parity", QSerialPort::Parity::NoParity);
    m_CheckCombox->addItem("Odd Parity", QSerialPort::Parity::OddParity);
    m_CheckCombox->addItem("Even Parity", QSerialPort::Parity::EvenParity);
    m_CheckCombox->addItem("Mark Parity", QSerialPort::Parity::MarkParity);
    m_CheckCombox->addItem("Space Parity", QSerialPort::Parity::SpaceParity);
    m_CheckCombox->setCurrentIndex(0);
    comToolBar->addWidget(checkLabel);
    comToolBar->addWidget(m_CheckCombox);

    auto stopLabel = new MyLabel(" 停止位：");
    m_StopCombox->addItem("1", QSerialPort::StopBits::OneStop);
    m_StopCombox->addItem("1.5", QSerialPort::StopBits::OneAndHalfStop);
    m_StopCombox->addItem("2", QSerialPort::StopBits::TwoStop);
    m_StopCombox->setCurrentIndex(0);
    comToolBar->addWidget(stopLabel);
    comToolBar->addWidget(m_StopCombox);

    comToolBar->addSeparator();
    m_OpenButton->setMinimumHeight(24);
    m_OpenButton->setIcon(m_OpenIcon);
    connect(m_OpenButton, &QAbstractButton::clicked, this, &MainWindow::openPort);
    comToolBar->addWidget(m_OpenButton);

    auto ctrlToolBar = addToolBar("Ctrl");
    ctrlToolBar->setFixedHeight(30);
    auto sendLabel = new MyLabel(" 发送：");
    m_SendFmtCombox->addItem("十六进制");
    m_SendFmtCombox->addItem("字符");
    m_SendFmtCombox->setCurrentIndex(0);
    connect(m_SendFmtCombox, QOverload<const QString &>::of(&QComboBox::currentIndexChanged), this, &MainWindow::sendFmtChange);
    ctrlToolBar->addWidget(sendLabel);
    ctrlToolBar->addWidget(m_SendFmtCombox);

    auto showLabel = new MyLabel(" 显示：");
    m_ShowFmtCombox->addItem("十六进制");
    m_ShowFmtCombox->addItem("字符");
    m_ShowFmtCombox->setCurrentIndex(0);
    connect(m_ShowFmtCombox, QOverload<const QString &>::of(&QComboBox::currentIndexChanged), this, &MainWindow::showFmtChange);
    ctrlToolBar->addWidget(showLabel);
    ctrlToolBar->addWidget(m_ShowFmtCombox);

    ctrlToolBar->addSeparator();
    m_ClearButton->setMinimumHeight(24);
    m_ClearButton->setIcon(m_ClearIcon);
    connect(m_ClearButton, &QPushButton::clicked, this, &MainWindow::clearBtnClicked);
    ctrlToolBar->addWidget(m_ClearButton);

    QHBoxLayout* bottomLayout = new QHBoxLayout();
    m_CmdComboBox->setEditable(true);
    m_CmdComboBox->setMinimumHeight(25);
    bottomLayout->addWidget(m_CmdComboBox);
    m_SendButton->setMaximumWidth(60);
    m_SendButton->setMinimumHeight(25);
    connect(m_SendButton, &QPushButton::clicked, this, &MainWindow::sendBtnClicked);
    bottomLayout->addWidget(m_SendButton);
    bottomLayout->setMargin(2);
    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    m_textEdit->setReadOnly(true);
    m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    mainLayout->addWidget(m_textEdit);
    mainLayout->addLayout(bottomLayout);
    mainLayout->setMargin(2);
    QWidget* mainWidget = new QWidget();

    mainWidget->setLayout(mainLayout);
    setCentralWidget(mainWidget);
}

void MainWindow::openPort()
{
    if (m_portOpened == true) {
        //m_recvThread.runStop();
        m_serialPort.close();
        m_OpenButton->setText("打开");
        m_OpenButton->setIcon(m_OpenIcon);
        m_textEdit->append("port closed success.\n");
        m_portOpened = 0;
    } else {
        m_serialPort.setPortName(m_PortCombox->currentText());
        m_serialPort.setBaudRate(m_BaudCombox->currentText().toInt());
        m_serialPort.setDataBits(static_cast<QSerialPort::DataBits>(m_DataCombox->currentText().toInt()));
        m_serialPort.setParity(static_cast<QSerialPort::Parity>(m_CheckCombox->currentData().toInt()));
        m_serialPort.setStopBits(static_cast<QSerialPort::StopBits>(m_StopCombox->currentData().toInt()));
        if (!m_serialPort.open(QIODevice::ReadWrite)) {
            m_textEdit->append("port opened failed.\n");
            return;
        }
        //m_recvThread.runStart(&m_serialPort);
        m_OpenButton->setText("关闭");
        m_OpenButton->setIcon(m_CloseIcon);
        m_textEdit->append("port opened success.\n");
        m_portOpened = 1;
    }
}

void MainWindow::formatHex(QTextStream &str, const QByteArray &data)
{
    const int fieldWidth = str.fieldWidth();
    const QTextStream::FieldAlignment alignment = str.fieldAlignment();
    const int base = str.integerBase();
    const QChar padChar = str.padChar();
    str.setIntegerBase(16);
    str.setPadChar(QLatin1Char('0'));
    str.setFieldAlignment(QTextStream::AlignRight);

    const unsigned char *p = reinterpret_cast<const unsigned char *>(data.constBegin());
    for (const unsigned char *end = p + data.size(); p < end; ++p) {
        str << ' ';
        str.setFieldWidth(2);
        str << unsigned(*p);
        str.setFieldWidth(fieldWidth);
    }
    str.setFieldAlignment(alignment);
    str.setPadChar(padChar);
    str.setIntegerBase(base);
}

void MainWindow::handleReadyRead()
{
    QByteArray bytes = m_serialPort.readAll();
    if (m_showHex){
        QString text;
        QTextStream str(&text);
        formatHex(str, bytes);
        m_textEdit->appendNoNL(text);
    } else {
        m_textEdit->appendNoNL(QString::fromUtf8(bytes));
    }
}

void MainWindow::threadRecvReq(const QString &text){
    m_textEdit->append(text);
}

void MainWindow::sendFmtChange(){
    if (m_SendFmtCombox->currentIndex() == 0){
        m_sendHex = 1;
    } else{
        m_sendHex = 0;
    }
}
void MainWindow::showFmtChange(){
    if (m_ShowFmtCombox->currentIndex() == 0){
        m_showHex = 1;
    } else {
        m_showHex = 0;
    }
}

void MainWindow::clearBtnClicked()
{
    m_textEdit->clear();
}

void MainWindow::sendBtnClicked()
{
    if (!m_portOpened){
        m_textEdit->append("port not opened");
        return;
    }
    QString text = m_CmdComboBox->currentText();
    if (m_sendHex){
        m_serialPort.write(HexStringToByteArray(text));
    } else {
        m_serialPort.write(text.toLatin1().data());
    }
}

void MainWindow::portComboxClicked(bool click)
{
    QString currentText = m_PortCombox->currentText();
    m_PortCombox->clear();
    QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo& info : infos) {
        m_PortCombox->addItem(info.portName());
    }
    if (m_PortCombox->findText(currentText) != -1){
        m_PortCombox->setCurrentText(currentText);
    } else {
        if (infos.size() > 0)
            m_PortCombox->setCurrentIndex(0);
    }
}

QByteArray MainWindow::HexStringToByteArray(QString HexString)
{
    bool ok;
    QByteArray ret;
    HexString = HexString.trimmed();
    HexString = HexString.simplified();
    HexString = HexString.replace(" ","");

    if (HexString.length() % 2 != 0){
        QMessageBox::warning(0,tr("错误"),QString("十六进制字符串长度为奇数"));
        return ret;
    }

    for (int i=0; i<HexString.length(); i+=2){
        QString h = HexString.mid(i, 2);
        char c = h.toInt(&ok,16)&0xFF;
        if(ok){
            ret.append(c);
        }else{
            qDebug()<<"非法的16进制字符："<< HexString;
            QMessageBox::warning(0,tr("错误"),QString("非法的16进制字符: \"%1\"").arg(h));
            ret.clear();
            return ret;
        }
    }
    qDebug()<<ret;
    return ret;
}

